﻿#region Using
#if NUNIT
using System;
using System.Data;
using System.IO;
using NMock2;
using NMock2.Internal;
using NUnit.Framework;
using TestClass = NUnit.Framework.TestFixtureAttribute;
using TestMethod = NUnit.Framework.TestAttribute;
using TestInitialize = NUnit.Framework.SetUpAttribute;
using TestCleanup = NUnit.Framework.TearDownAttribute;
using TestContext = System.Object;
#else
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Category = Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute;
#endif
#endregion

namespace NMock3.Tests
{
	[TestClass]
	public class OrderedMessageTests
	{
		private MockFactory _factory = new MockFactory();
		private Mock<IOrderedMethods> mock;

		[TestInitialize]
		public void TestInit()
		{
			_factory.ClearExpectations();
			mock = _factory.CreateMock<IOrderedMethods>();
		}

		[TestCleanup]
		public void TestClean()
		{
			_factory.VerifyAllExpectationsHaveBeenMet();
		}

		[TestMethod]
		public void MessageTest1()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call1());
			}
			mock.MockObject.Call1();
		}

		[TestMethod]
		public void MessageTest2()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call2());
				mock.Expects.One.Method(m => m.Call1());
			}

			try
			{
				mock.MockObject.Call1();
				mock.MockObject.Call2(); //will never hit
			}
			catch (ExpectationException err)
			{
				Assert.AreEqual(@"
Unexpected invocation of:
  orderedMethods.Call1()

  Note: You are using an Ordered Mock.  The call may be out of order.

Expected:
  Ordered:
    1 time: orderedMethods.Call2(any arguments) [called 0 times]
    1 time: orderedMethods.Call1(any arguments) [called 0 times]

", err.Message);
			}

			_factory.SuppressUnexpectedAndUnmetExpectations();
		}

		[TestMethod]
		public void MessageTest3()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}
			}

			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call3();


		}

		[TestMethod]
		public void MessageTest6()
		{
			using (_factory.Ordered)
			{
				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

			}

			mock.MockObject.Call4();
			mock.MockObject.Call3();
			mock.MockObject.Call1();
			mock.MockObject.Call2();
			try
			{
				mock.MockObject.Call3();
			}
			catch (ExpectationException err)
			{
				Assert.AreEqual(@"
Unexpected invocation of:
  orderedMethods.Call3()
Expected:
", err.Message);
				_factory.SuppressUnexpectedAndUnmetExpectations();
			}


		}

		[TestMethod]
		public void MessageTest4()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());

					using (_factory.Ordered)
					{
						mock.Expects.One.Method(m => m.Call5());
						mock.Expects.One.Method(m => m.Call6());
					}
				}
			}

			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call3();
			try
			{
				mock.MockObject.Call6();
			}
			catch (ExpectationException err)
			{
				Assert.AreEqual(@"
Unexpected invocation of:
  orderedMethods.Call6()

  Note: You are using an Ordered Mock.  The call may be out of order.

Expected:
  Ordered:
    Unordered:
      Ordered:
        1 time: orderedMethods.Call5(any arguments) [called 0 times]
        1 time: orderedMethods.Call6(any arguments) [called 0 times]



", err.Message);
			}

			_factory.SuppressUnexpectedAndUnmetExpectations();
		}

		[TestMethod]
		public void MessageTest5()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());

					using (_factory.Ordered)
					{
						mock.Expects.One.Method(m => m.Call5());
						mock.Expects.One.Method(m => m.Call6());
					}
				}
			}

			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call3();
			mock.MockObject.Call5();
			mock.MockObject.Call6();
			try
			{
				mock.MockObject.Call7();
			}
			catch (ExpectationException err)
			{
				Assert.AreEqual(@"
Unexpected invocation of:
  orderedMethods.Call7()
Expected:
", err.Message);
			}

			_factory.SuppressUnexpectedAndUnmetExpectations();
		}

		[TestMethod]
		public void MessageTest7()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				mock.Expects.One.Method(m => m.Call5());
				mock.Expects.One.Method(m => m.Call6());
			}

			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call3();
			mock.MockObject.Call5();
			mock.MockObject.Call6();
		}

		[TestMethod]
		public void MessageTest8()
		{
			using (_factory.Unordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				mock.Expects.One.Method(m => m.Call5());
				mock.Expects.One.Method(m => m.Call6());
			}

			mock.MockObject.Call2();
			mock.MockObject.Call1();
			mock.MockObject.Call3();
			mock.MockObject.Call4();
			mock.MockObject.Call6();
			mock.MockObject.Call5();
		}

		[TestMethod]
		public void MessageTest9()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				mock.Expects.One.Method(m => m.Call5());
				mock.Expects.One.Method(m => m.Call6());
			}

			try
			{
				mock.MockObject.Call2();
			}
			catch (ExpectationException err)
			{
				Assert.AreEqual(@"
Unexpected invocation of:
  orderedMethods.Call2()

  Note: You are using an Ordered Mock.  The call may be out of order.

Expected:
  Ordered:
    1 time: orderedMethods.Call1(any arguments) [called 0 times]
    1 time: orderedMethods.Call2(any arguments) [called 0 times]
    Unordered:
      1 time: orderedMethods.Call3(any arguments) [called 0 times]
      1 time: orderedMethods.Call4(any arguments) [called 0 times]

    1 time: orderedMethods.Call5(any arguments) [called 0 times]
    1 time: orderedMethods.Call6(any arguments) [called 0 times]

", err.Message);
			}

			_factory.SuppressUnexpectedAndUnmetExpectations();
		}

		[TestMethod]
		public void MessageTest10()
		{
			using (_factory.Ordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				mock.Expects.One.Method(m => m.Call5());
				mock.Expects.One.Method(m => m.Call6());
			}

			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call3();

			try
			{
				mock.MockObject.Call6();
			}
			catch (ExpectationException err)
			{
				Assert.AreEqual(@"
Unexpected invocation of:
  orderedMethods.Call6()
Expected:
", err.Message);
			}

			_factory.SuppressUnexpectedAndUnmetExpectations();
		}

		[TestMethod]
		public void MessageTest11()
		{
			using (_factory.Unordered)
			{
				mock.Expects.One.Method(m => m.Call1());
				mock.Expects.One.Method(m => m.Call2());

				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				mock.Expects.One.Method(m => m.Call5());
				mock.Expects.One.Method(m => m.Call6());
			}

			mock.MockObject.Call2();
			mock.MockObject.Call1();

			try
			{
				mock.MockObject.Call4();
			}
			catch (ExpectationException err)
			{
				Assert.AreEqual(@"
Unexpected invocation of:
  orderedMethods.Call4()

  Note: You are using an Ordered Mock.  The call may be out of order.

Expected:
  Unordered:
    Ordered:
      1 time: orderedMethods.Call3(any arguments) [called 0 times]
      1 time: orderedMethods.Call4(any arguments) [called 0 times]

    1 time: orderedMethods.Call5(any arguments) [called 0 times]
    1 time: orderedMethods.Call6(any arguments) [called 0 times]

", err.Message);
			}

			_factory.SuppressUnexpectedAndUnmetExpectations();
		}

		[TestMethod]
		public void MessageTest12()
		{
			using (_factory.Unordered)
			{
				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call1());
					mock.Expects.One.Method(m => m.Call2());
				}

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call5());
					mock.Expects.One.Method(m => m.Call6());
				}

				mock.Expects.One.Method(m => m.Call7());
			}

			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call3();
			mock.MockObject.Call5();
			mock.MockObject.Call6();
			mock.MockObject.Call7();
		}

		[TestMethod]
		public void MessageTest13()
		{
			using (_factory.Unordered)
			{
				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call1());
					mock.Expects.One.Method(m => m.Call2());
				}

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call5());
					mock.Expects.One.Method(m => m.Call6());
				}

				mock.Expects.One.Method(m => m.Call7());
			}

			mock.MockObject.Call5();
			mock.MockObject.Call6();
			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call3();
			mock.MockObject.Call7();
		}

		[TestMethod]
		public void MessageTest14()
		{
			using (_factory.Unordered)
			{
				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call1());
					mock.Expects.One.Method(m => m.Call2());
				}

				using (_factory.Unordered)
				{
					mock.Expects.One.Method(m => m.Call3());
					mock.Expects.One.Method(m => m.Call4());
				}

				using (_factory.Ordered)
				{
					mock.Expects.One.Method(m => m.Call5());
					mock.Expects.One.Method(m => m.Call6());
				}

				mock.Expects.One.Method(m => m.Call7());
			}

			mock.MockObject.Call1();
			mock.MockObject.Call2();
			mock.MockObject.Call4();
			mock.MockObject.Call7();
			mock.MockObject.Call3();
			mock.MockObject.Call5();
			mock.MockObject.Call6();
		}

		public interface IOrderedMethods
		{
			void Call1();
			void Call2();
			void Call3();
			void Call4();
			void Call5();
			void Call6();
			void Call7();
		}
	}
}
